package com.aboverock.module.system.web;

import com.aboverock.autoconfigure.util.JwtUtil;
import com.aboverock.common.domain.Datagrid;
import com.aboverock.common.domain.Result;
import com.aboverock.common.enums.MessageSourceKey;
import com.aboverock.common.enums.UserSexEnum;
import com.aboverock.common.enums.UserStatusEnum;
import com.aboverock.common.enums.UserTypeEnum;
import com.aboverock.common.helper.PageHelper;
import com.aboverock.core.security.annotation.SecurityLog;
import com.aboverock.core.security.enums.SecurityTypeEnum;
import com.aboverock.core.shiro.util.ShiroHashEncryptUtil;
import com.aboverock.core.spring.web.StringIdBaseController;
import com.aboverock.module.shiro.util.ShiroCacheUtil;
import com.aboverock.module.system.domain.User;
import com.aboverock.module.system.enums.StatisticalUnit;
import com.aboverock.module.system.i18n.KbSmartMessageSourceKey;
import com.aboverock.module.system.service.LogService;
import com.aboverock.module.system.service.UserRoleService;
import com.aboverock.module.system.service.UserService;
import com.aboverock.module.system.utils.UserInfoUtil;
import com.aboverock.module.system.validator.groups.LocalUserGroup;
import com.aboverock.module.system.validator.groups.UpdateLocalUserGroup;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import javax.validation.groups.Default;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

// import freemarker.template.TemplateException;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author Rock Wang
 * @since 2018-04-02
 */
@RestController
@RequestMapping("system/user")
@Validated
public class UserController extends StringIdBaseController<User> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    /** 数据湖员工信息最小查询长度. */
    private static final int MIN_QUERY_LEN = 3;

    @Autowired
    private UserService userService;

    // @Autowired
    // private DatalakeService datalakeService;
    //
    // @Autowired
    // private SmartMailService smartMailService;

    @ApiOperation(value = "是否支持本地用户")
    @GetMapping("local/isSupport")
    public Result isSupportLocalUser() {
        return Result.success(userService.isSupportLocalUser());
    }

    @ApiOperation(value = "获取所有用户及其角色")
    @Override
    public Result all(HttpServletRequest request) {
        List<User> users = userService.getUsersWithRoles();
        return Result.success(users);
    }

    @ApiOperation(value = "分页获取用户及其角色")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "current", value = "当前页码", defaultValue = CURRENT_PAGE_DEFAULT, required = false, dataType = "long"),
        @ApiImplicitParam(name = "pageSize", value = "每页数量", defaultValue = PAGE_SIZE_DEFAULT, required = false, dataType = "long") })
    @Override
    public Result page(HttpServletRequest request) {
        Page<User> page = PageHelper.page(User.class);
        Long start = (page.getCurrent() - 1) * page.getSize();
        List<User> users = userService.getUsersWithRoles(start, page.getSize());

        int total = userService.count(null);
        page.setTotal(total);
        page.setRecords(users);
        return Result.success(new Datagrid<User>(page));
    }

    /**
     * Gets the current user.
     *
     * @return the current user
     */
    @ApiOperation(value = "获取当前登录用户及其角色")
    @GetMapping("current")
    public Result getCurrentUser() {
        User currentUser = userService.getCurrentUserWithRoles();
        if (null == currentUser) {
            return Result.fail();
        }

        return Result.success(currentUser);
    }

    /**
     * 模糊查询数据库用户.
     *
     * @param loginName the login name
     * @return the result
     */
    @ApiOperation(value = "根据登录名模糊查询系统中用户")
    @GetMapping("loginName/{loginName}")
    public Result fuzzyQuery(@PathVariable String loginName) {
        List<User> users = userService.fuzzyQueryByLoginName(loginName);
        return Result.success(users);
    }

    /**
     * 模糊查询数据湖用户信息（会包含其部门信息）.
     *
     * @param loginName the login name
     * @return the result
     * @throws DatalakeRequestException the datalake request exception
     * @throws DatalakeDataParseException the datalake data parse exception
     */
    // @ApiOperation(value = "根据登录名模糊查询数据湖中用户")
    // @ApiImplicitParams({
    //     @ApiImplicitParam(name = "current", value = "当前页码", defaultValue = CURRENT_PAGE_DEFAULT, required = false, dataType = "long"),
    //     @ApiImplicitParam(name = "pageSize", value = "每页数量", defaultValue = PAGE_SIZE_DEFAULT, required = false, dataType = "long") })
    // @GetMapping("datalake/loginName/{loginName}")
    // public Result fuzzyQueryFromDatalake(
    //         @Length(min = MIN_QUERY_LEN, message = "{smart.constraints.Length.min.message}") @PathVariable String loginName)
    //         throws DatalakeRequestException, DatalakeDataParseException {
    //     Page<User> page = PageHelper.page(User.class);
    //     return Result.success(datalakeService.getUserInfoByLoginNameContains(loginName, page));
    // }

    /**
     * 导入数据湖用户信息.
     *
     * @param users the users
     * @return the result
     */
    @ApiOperation(value = "数据湖导入用户")
    @PostMapping("datalake/import")
    public Result importUserFromDatalake(@RequestBody List<User> users) {
        try {
            List<User> importUsers = userService.saveDataLakeEmpInfoToDb(users);
            return Result.success(importUsers);
        } catch (Exception e) {
            logger.warn("Data-Smart:导入数据湖用户失败", e);
        }
        return Result.fail();
    }

    /**
     * 锁定用户帐号(超级管理员不会被锁定).
     *
     * @param users the users
     * @return the result
     */
    @ApiOperation(value = "锁定多个用户帐户")
    @SecurityLog(securityType = SecurityTypeEnum.USER_LOCK)
    @PatchMapping("action/lock")
    public Result lock(@RequestBody List<User> users) {
        List<String> userIds = new ArrayList<String>(users.size());
        for (User user : users) {
            if (!UserInfoUtil.isSuperAdmin(user)) {
                userIds.add(user.getId());
            }
        }

        if (userService.lockUsersByUserId(userIds)) {
            ShiroCacheUtil.removeAuthecticationInfo(users);
            ShiroCacheUtil.removeAuthorizationInfo(users);
            return Result.success();
        }

        return Result.fail();
    }

    /**
     * 解锁用户帐号.
     *
     * @param users the users
     * @return the result
     */
    @ApiOperation(value = "解锁多个用户帐户")
    @SecurityLog(securityType = SecurityTypeEnum.USER_UNLOCK)
    @PatchMapping("action/unlock")
    public Result unlock(@RequestBody List<User> users) {
        List<String> userIds = new ArrayList<String>(users.size());
        for (User user : users) {
            userIds.add(user.getId());
        }

        if (userService.unlockUsersByUserId(userIds)) {
            return Result.success();
        }

        return Result.fail();
    }

    /**
     * 删除用户(不能删除超级管理员).
     *
     * @param users the users
     * @return the result
     */
    @ApiOperation(value = "删除多个用户帐户")
    @SecurityLog(securityType = SecurityTypeEnum.USER_DELETE)
    @DeleteMapping
    public Result delete(@RequestBody List<User> users) {
        List<String> userIds = new ArrayList<String>(users.size());
        for (User user : users) {
            if (!UserInfoUtil.isSuperAdmin(user)) {
                userIds.add(user.getId());
            }
        }

        try {
            userService.deleteByIds(userIds);
            ShiroCacheUtil.removeAuthecticationInfo(users);
            ShiroCacheUtil.removeAuthorizationInfo(users);
            return Result.success();
        } catch (SQLException e) {
            logger.warn("Data-Smart:删除用户失败", e);
        }
        return Result.fail();
    }

    @Autowired
    private UserRoleService userRoleService;

    private ReentrantLock lock = new ReentrantLock();
    private int pwdLength = 10;

    @ApiOperation(value = "添加本地用户")
    @PostMapping("local")
    public Result save(@RequestParam String systemName, @RequestParam String systemUrl,
            @Validated({ Default.class, LocalUserGroup.class }) @RequestBody User user) {
        lock.lock();
        try {
            String loginName = user.getLoginName();
            user.setLoginName(UserInfoUtil.addSuffix2LocalUserLoginName(loginName));

            String password = RandomStringUtils.randomAlphanumeric(pwdLength);
            user.setPassword(ShiroHashEncryptUtil.encrypt(password));

            user.setSex(UserSexEnum.UNKNOWN.getValue());
            user.setType(UserTypeEnum.LOCAL.getValue());
            user.setStatus(UserStatusEnum.NORMAL.getValue());
            if (userService.save(user)) {
                if (!userRoleService.addCommonRole(user.getId())) {
                    logger.warn("Data-Smart: 给用户{}添加通用角色失败", user.getLoginName());
                }

                Map<String, String> model = new HashMap<>(3);
                model.put("loginName", loginName);
                model.put("password", password);
                model.put("systemUrl", systemUrl);

                // try {
                //     smartMailService.sendByTemplate(user.getEmail(), systemName + "帐号开通",
                //             "/mail/local-user-info-email.ftl", model);
                // } catch (IOException | TemplateException e) {
                //     logger.warn("Data-Smart: 给用户{}发送帐号通知邮件失败", loginName, e);
                // }
                return Result.success(user);
            }

            return Result.fail();
        } finally {
            lock.unlock();
        }
    }

    @Autowired
    private Validator validator;

    @ApiOperation(value = "更新本地帐号密码")
    @PatchMapping("password")
    public Result updatePassword(@RequestBody User user) {
        String loginName = JwtUtil.getLoginName();
        user.setLoginName(UserInfoUtil.addSuffix2LocalUserLoginName(user.getLoginName()));
        // 用户只可以修改自己的密码
        if (user.getLoginName() != null && !user.getLoginName().equalsIgnoreCase(loginName)) {
            return Result.fail(MessageSourceKey.Common.COMMON_OPERATE_REFUSE_KEY);
        }

        User u = userService.getLocalUserByLoginName(loginName);
        if (null == u) {
            return Result.fail(KbSmartMessageSourceKey.LOCAL_USER_NOT_FOUND);
        }
        user.setType(u.getType());
        Set<ConstraintViolation<User>> constraintViolations = validator.validate(user,
                UpdateLocalUserGroup.class);
        if (!constraintViolations.isEmpty()) {
            throw new ConstraintViolationException(constraintViolations);
        }

        if (userService.updateLocalUserPassword(user)) {
            return Result.success();
        }
        return Result.fail();
    }

    @ApiOperation(value = "获取系统所有用户信息，供工程IT平台统计使用")
    @GetMapping("count")
    public Result getUserNum() {
        return Result.success(userService.list(null));
    }

    @Autowired
    private LogService logService;

    @ApiOperation(value = "统计系统使用情况，供工程IT平台统计使用")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "startTime", value = "统计起始时间戳", required = false, dataType = "long"),
        @ApiImplicitParam(name = "unit", value = "统计单位(WEEK, MONTH, YEAR)，大小写敏感", defaultValue = "MONTH", required = false) })
    @GetMapping("usage")
    public Result getUseStatisticalInfo(@RequestParam(required = false) Long startTime,
            @RequestParam(defaultValue = "MONTH") StatisticalUnit unit) {
        if (null == startTime) {
            LocalDate localDate = LocalDate.now().minusYears(1);
            startTime = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
        }

        return Result.success(logService.getUseStatisticalInfo(startTime, unit));
    }

    @Override
    @ApiOperation(value = "禁用该通用接口")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result getById(String id) {
        return null;
    }

    @Override
    @ApiOperation(value = "禁用该通用接口")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result save(User entity) {
        return null;
    }

    @Override
    @ApiOperation(value = "禁用该通用接口")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result update(String id, User entity) {
        return null;
    }

    @Override
    @ApiOperation(value = "禁用该通用接口")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result delete(String id) {
        return null;
    }

}
